﻿using EcoSystem.Enums;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;

namespace EcoSystem
{
    public class FileResourceAppService : CrudAppService<
        FileResource,
        FileResourceDto,
        Guid,
        GetFileResourceInput,
        CreateOrUpdateFileResourceDto,
        CreateOrUpdateFileResourceDto>, IFileResourceAppService
    {
        private readonly IRepository<DirResource, Guid> _dirRepository;
        private readonly ResourceUploadOptions _uploadOptions;
        public FileResourceAppService(
            IRepository<FileResource, Guid> repository,
            IRepository<DirResource, Guid> dirRepository,
            IOptions<ResourceUploadOptions> uploadOptions
            ) : base(repository)
        {
            _dirRepository = dirRepository;
            _uploadOptions = uploadOptions.Value;
        }


        public override async Task<PagedResultDto<FileResourceDto>> GetListAsync(GetFileResourceInput input)
        {
            var query = (await Repository.GetQueryableAsync()).AsNoTracking()
                   .WhereIf(!input.Name.IsNullOrWhiteSpace(), x => x.BucketName.Contains(input.Name) || x.FileName.Contains(input.Name) || x.DirPath.Contains(input.Name))
                   .WhereIf(!input.BucketName.IsNullOrWhiteSpace(), x => x.BucketName == input.BucketName)
                   .WhereIf(!input.DirPath.IsNullOrWhiteSpace(), x => x.DirPath == input.DirPath)
                   .WhereIf(input.Type.HasValue, x => x.FileType == input.Type);
            var total = await query.CountAsync();
            var items = await query.OrderByDescending(x => x.Id).PageBy(input).ToListAsync();
            return new PagedResultDto<FileResourceDto>()
            {
                Items = await MapToGetListOutputDtosAsync(items),
                TotalCount = total
            };
        }

        public async Task<List<FileResourceDto>> GetAllListAsync(GetFileResourceInput input)
        {
            var query = (await Repository.GetQueryableAsync()).AsNoTracking()
                        .WhereIf(!input.Name.IsNullOrWhiteSpace(), x => x.BucketName.Contains(input.Name) || x.FileName.Contains(input.Name) || x.DirPath.Contains(input.Name))
                        .WhereIf(!input.Extension.IsNullOrWhiteSpace(), x => x.Extension == input.Extension)
                        .WhereIf(input.Type.HasValue, x => x.FileType == input.Type);
            var items = await query.OrderByDescending(x => x.Id).ToListAsync();
            return await MapToGetListOutputDtosAsync(items);
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<FileResourceDto> UploadFileAsync(UploadFileResourceInputDto input)
        {
            string bucketName = input.BucketName ?? _uploadOptions.DefaultBucketName;
            string pathPrefix = _uploadOptions.BaseUploadPath.TrimEnd('/') + "/" + bucketName;
            string fileName = string.IsNullOrWhiteSpace(input.FileName) ? input.File.FileName : input.FileName;
            string extension = Path.GetExtension(input.File.FileName)?.ToLower();
            FileType fileType = FileHelper.CreateResourceType(extension);
            string path = FileHelper.CreateFilePath(pathPrefix, fileType, extension);
            //保存文件 
            await FileHelper.SaveFileAsync(input.File, path);

            //写入数据
            FileResource entity = new FileResource()
            {
                FileName = fileName,
                BucketName = bucketName,
                FileType = fileType,
                FilePath = path,
                FileSize = input.File.Length,
                Extension = extension,
            };
            EntityHelper.TrySetId(entity, () => GuidGenerator.Create());
            if (input.DirId.HasValue)
            {
                var dir = await (await _dirRepository.GetQueryableAsync())
                    .AsNoTracking().FirstOrDefaultAsync(x => x.Id == input.DirId);
                entity.DirPath = dir.DirPath;
            }
            else if (input.Dir.IsNullOrWhiteSpace())
            {
                entity.DirPath = input.BucketName + "/" + input.Dir;
            }
            await Repository.InsertAsync(entity, true);
            return MapToGetListOutputDto(entity);
        }

        public async Task<FileResourceDto> GetForNameAsync(string objectName)
        {
            string filePath = objectName.Substring(0, objectName.LastIndexOf("/"));
            string fileName = objectName.Substring(objectName.LastIndexOf("/") + 1);
            var query = await Repository.GetQueryableAsync();
            var entity = await query.AsNoTracking().FirstOrDefaultAsync(x => x.DirPath == filePath && x.FileName == fileName);
            return MapToGetOutputDto(entity);
        }
    }
}
